package com.guojiang.guoaicodemother.utils;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.guojiang.guoaicodemother.exception.BusinessException;
import com.guojiang.guoaicodemother.exception.ErrorCode;
import io.github.bonigarcia.wdm.WebDriverManager;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.stereotype.Component;

import java.io.File;
import java.time.Duration;
import java.util.UUID;

/**
 * 浏览器截图工具类
 *
 * @Author: guojiang
 */
@Slf4j
@Component
public class WebScreenshotUtils {

    // private final static WebDriver webDriver;

    // 为了避免多线程下共享一个 WebDriver 导致结果出错的问题，使用 ThreadLocal 来保证每个线程都拥有自己的 WebDriver 实例
    // 我们的业务来看，一个线程生成一个应用封面即可，不需要一个线程去生成很多应用封面，所以使用 ThreadLocal 是合适的
    private static final ThreadLocal<WebDriver> webDriverThreadLocal = new ThreadLocal<>();

    /**
     * 全局静态初始化，避免重复初始化
     */
    public static WebDriver getWebDriver() {
        WebDriver webDriver = webDriverThreadLocal.get();
        if (webDriver == null) {
            final int DEFAULT_WIDTH = 1600;
            final int DEFAULT_HEIGHT = 900;
            webDriver = initChromeDriver(DEFAULT_WIDTH, DEFAULT_HEIGHT);
            webDriverThreadLocal.set(webDriver);
        }
        return webDriver;
    }

    /**
     * 退出时销毁
     */
    @PreDestroy
    public void destroy() {
        WebDriver webDriver = webDriverThreadLocal.get();
        // 如果 webDriver 不为空，则销毁
        if (webDriver != null) {
            try {
                webDriver.quit(); // 释放浏览器进程资源
            } catch (Exception e) {
                log.error("WebDriver 销毁异常，异常信息：{}", e.getMessage(), e);
            } finally {
                webDriverThreadLocal.remove(); // 关键：清除 ThreadLocal 中的值
            }
        }
    }

    /**
     * 生成并保存网页截图
     *
     * @param webUrl
     * @return 压缩后的截图文件路径，失败返回 null
     */
    public static String saveWebScreenshot(String webUrl) {
        // 校验
        if (StrUtil.isBlank(webUrl)) {
            log.error("截图失败，网页地址为空");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "截图失败，网页地址为空");
        }
        // 创建临时目录
        String rootPath = System.getProperty("user.dir") + "/tmp/screenshots/"
                + UUID.randomUUID().toString().substring(0, 8);
        FileUtil.mkdir(rootPath);
        // 图片后缀
        final String IMAGE_SUFFIX = ".png";
        // 原始图片保存路径
        String originImageSavePath = rootPath + File.separator + RandomUtil.randomNumbers(5) + IMAGE_SUFFIX;
        try {
            // 获取 WebDriver 实例
            WebDriver webDriver = getWebDriver();
            // 访问网页
            webDriver.get(webUrl);
            // 等待页面加载完成
            waitForPageLoad(webDriver);
            log.info("开始进行截图...");
            // 截图
            byte[] screenshotBytes = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.BYTES);
            // 保存原始图片
            log.info("保存原始截图到临时目录中...");
            saveImage(screenshotBytes, originImageSavePath);
            log.info("原始截图保存成功，原始图片路径：{}", originImageSavePath);
            // 压缩图片
            final String COMPRESSED_IMAGE_SUFFIX = "_compressed.jpg";
            log.info("压缩原始截图中...");
            String compressedImageSavePath = rootPath + File.separator
                    + RandomUtil.randomNumbers(5) + COMPRESSED_IMAGE_SUFFIX;
            compressImage(originImageSavePath, compressedImageSavePath);
            log.info("压缩截图成功，压缩图片路径：{}", compressedImageSavePath);
            // 删除原始图片
            FileUtil.del(originImageSavePath);
            // 返回压缩图片路径
            return compressedImageSavePath;
        } catch (Exception e) {
            log.error("截图失败，访问路径：{}，错误信息：{}", webUrl, e.getMessage(), e);
            // 截图失败不用抛出异常，返回 null，外层方法根据返回值判断是否截图成功
            return null;
        } finally {
            // 每次使用完后清理
            WebDriver webDriver = webDriverThreadLocal.get();
            if (webDriver != null) {
                webDriver.quit();
                webDriverThreadLocal.remove();
            }
        }
    }

    /**
     * 保存截图到文件
     *
     * @param imageBytes
     * @param imagePath
     */
    private static void saveImage(byte[] imageBytes, String imagePath) {
        try {
            FileUtil.writeBytes(imageBytes, imagePath);
        } catch (Exception e) {
            log.error("保存截图失败：{}", imagePath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "保存应用封面失败");
        }
    }

    /**
     * 压缩截图
     *
     * @param originalImagePath
     * @param compressedImagePath
     */
    private static void compressImage(String originalImagePath, String compressedImagePath) {
        // 图片压缩质量（0.1f = 10% 图片质量）
        final float COMPRESS_QUALITY = 0.6f;
        try {
            ImgUtil.compress(FileUtil.file(originalImagePath), FileUtil.file(compressedImagePath), COMPRESS_QUALITY);
        } catch (Exception e) {
            log.error("压缩截图失败：{} -> {}", originalImagePath, compressedImagePath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "压缩截图失败");
        }
    }

    /**
     * 等待页面加载完成
     *
     * @param driver
     */
    private static void waitForPageLoad(WebDriver driver) {
        try {
            // 创建等待页面加载对象
            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
            // 等待 document.readyState 为complete
            wait.until(webDriver ->
                    ((JavascriptExecutor) webDriver)
                            .executeScript("return document.readyState")
                            .equals("complete")
            );
            // 额外等待一段时间，确保动态内容加载完成
            Thread.sleep(2000);
            log.info("页面加载完成");
        } catch (Exception e) {
            log.error("等待页面加载时出现异常，继续执行截图", e);
        }
    }

    /**
     * 初始化 Chrome 浏览器驱动（改造后：手动指定 ChromeDriver 路径）
     */
    private static WebDriver initChromeDriver(int width, int height) {
        try {
            // ========== 关键改造：手动指定 ChromeDriver 路径 ==========
            // 1. 替换为你本地 chromedriver.exe 的实际路径（Windows 示例）
            //    若为 Linux/Mac，路径格式如："/usr/local/bin/chromedriver"
            String chromeDriverPath = "C:/XingQiuCode/ChromeDriver/chromedriver.exe";
            System.setProperty("webdriver.chrome.driver", chromeDriverPath);

            // ========== 以下配置与原逻辑保持一致 ==========
            ChromeOptions options = new ChromeOptions();
            // 无头模式（无界面运行）
            options.addArguments("--headless");
            // 禁用 GPU 加速（避免部分环境报错）
            options.addArguments("--disable-gpu");
            // 禁用沙盒（Docker 或权限受限环境需开启）
            options.addArguments("--no-sandbox");
            // 禁用 /dev/shm 使用（避免内存不足问题）
            options.addArguments("--disable-dev-shm-usage");
            // 设置窗口尺寸
            options.addArguments(String.format("--window-size=%d,%d", width, height));
            // 禁用浏览器扩展
            options.addArguments("--disable-extensions");
            // 自定义 User-Agent
            options.addArguments("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");

            // 创建 Chrome 驱动实例
            WebDriver driver = new ChromeDriver(options);
            // 页面加载超时（30秒）
            driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(30));
            // 元素隐式等待（10秒）
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));

            return driver;
        } catch (Exception e) {
            log.error("初始化应用封面 Chrome 浏览器失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "初始化应用封面 Chrome 浏览器失败");
        }
    }

    /**
     * 初始化 Chrome 浏览器驱动
     */
    @Deprecated
    private static WebDriver initChromeDriverAuto(int width, int height) {
        try {
            // 自动管理 ChromeDriver
            WebDriverManager.chromedriver().setup();
            // 配置 Chrome 选项
            ChromeOptions options = new ChromeOptions();
            // 无头模式
            options.addArguments("--headless");
            // 禁用GPU（在某些环境下避免问题）
            options.addArguments("--disable-gpu");
            // 禁用沙盒模式（Docker环境需要）
            options.addArguments("--no-sandbox");
            // 禁用开发者shm使用
            options.addArguments("--disable-dev-shm-usage");
            // 设置窗口大小
            options.addArguments(String.format("--window-size=%d,%d", width, height));
            // 禁用扩展
            options.addArguments("--disable-extensions");
            // 设置用户代理
            options.addArguments("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
            // 创建驱动
            WebDriver driver = new ChromeDriver(options);
            // 设置页面加载超时
            driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(30));
            // 设置隐式等待
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
            return driver;
        } catch (Exception e) {
            log.error("初始化应用封面 Chrome 浏览器失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "初始化应用封面 Chrome 浏览器失败");
        }
    }
}
